package com.example.hello.service.impl;

import com.example.hello.mapper.CreditLogMapper;
import com.example.hello.mapper.UserBorrowCertificateMapper;
import com.example.hello.mapper.UserMapper;
import com.example.hello.pojo.CreditLog;
import com.example.hello.pojo.User;
import com.example.hello.pojo.UserBorrowCertificate;
import com.example.hello.service.CreditService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class CreditServiceImpl implements CreditService {

    @Autowired private UserMapper userMapper;
    @Autowired private CreditLogMapper logMapper;
    @Autowired private UserBorrowCertificateMapper userBorrowCertificateMapper;

    private void adjustCredit(Long userId, int delta, String reason, Long relatedId) {
        // 1. 读变化前的信誉
        int before = userMapper.getCredit(userId);

        // 如果是加分，且已经满分，则直接跳过
        if (delta > 0 && before >= 100) {
            return;
        }

        int after  = Math.min(100, Math.max(0, before + delta));

        // 2. 写流水
        CreditLog log = new CreditLog();
        log.setUserId(userId);
        log.setChange(delta);
        log.setReason(reason);
        log.setRelatedId(relatedId);
        log.setCreditBefore(before);
        log.setCreditAfter(after);
        logMapper.insert(log);

        // 3. 更新用户表
        userMapper.updateCredit(userId, delta);
    }

    @Override
    @Transactional
    public void onReturn(Long userId, Long borrowId, Date borrowDate, Date returnDate) {
        User user = userMapper.getById(userId);
        UserBorrowCertificate certificate = userBorrowCertificateMapper.getById(user.getCertificateId());


        // 计算 due_date
        var due = borrowDate.toInstant().atZone(ZoneId.systemDefault())
                     .toLocalDate().plusDays(certificate.getMaxBorrowDay());
        var actual = returnDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        long overdueDays = ChronoUnit.DAYS.between(due, actual);

        int delta;
        String reason;
        if (overdueDays <= 0) {
            delta = +2;
            reason = "按时还书";
        } else {
            delta = -(int)Math.min(overdueDays, 10);
            reason = "逾期还书";
        }
        adjustCredit(userId, delta, reason, borrowId);
    }

    /** 每周一零点自动 +5 */
    @Override
    @Scheduled(cron = "0 0 0 * * MON")
    @Transactional
    public void weeklyRestore() {
        List<Long> all = userMapper.listAllUserIds();
        for (Long uid : all) {
            adjustCredit(uid, +5, "每周＋5分", null);
        }
    }

    @Override
    public Integer getCurrentCredit(Long userId) {
        return userMapper.getCredit(userId);
    }

    @Override
    public List<CreditLog> getCreditLogs(Long userId) {
        return logMapper.selectByUserId(userId);
    }
}